package com.yuan.farmerwork.ynblog.aspect;

import com.yuan.farmerwork.ynblog.utils.RedisService;
import com.yuan.farmerwork.ynblog.utils.constants.RedisKeyConstants;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.util.Date;

/**
 * 访问切面.
 *
 * <p>
 * 对所有controller层做切面，做访问次数的统计，通过{@link RedisService#set(String key, Object value) set}来对访问次数做统计，
 * 同时记录请求访问的的接口及其方法，客户端ip及接口请求所花费的时间。
 * </p>
 *
 * @author JsY
 * @date 2020-03-25 09:21
 */
@Aspect
@Component
public class VisitAspect {

    public Logger logger = LoggerFactory.getLogger(this.getClass());

    /**
     * 所需的redis服务依赖注入的service
     */
    @Autowired
    private RedisService redisService;

    /**
     * 设置的切边 对所有Controller层做切面.
     *
     * @return
     */
    @Pointcut("execution(* com.yuan.farmerwork.ynblog.rest.*.*(..))")
    public void pointcut() {

    }

    /**
     * 环绕通知执行.
     *
     * @param pjp 继承了<tt>JoinPoint</tt>。是在<tt>JoinPoint</tt>的基础上暴露出 proceed 这个方法
     * @return 启动目标方法执行的参数
     * @throws Throwable
     */
    @Around("pointcut()")
    public Object before(ProceedingJoinPoint pjp) throws Throwable {
        long startTime = System.currentTimeMillis();
        //统计访问次数
        Object visitNum = redisService.get(RedisKeyConstants.REDIS_KEY_VISIT_NUM);
        if (visitNum == null) {
            redisService.set(RedisKeyConstants.REDIS_KEY_VISIT_NUM, 1);
        } else {
            Integer visitNumBig = (Integer) visitNum;
            redisService.set(RedisKeyConstants.REDIS_KEY_VISIT_NUM, visitNumBig + 1);
        }
        //记录访问信息
        Object retVal = pjp.proceed();
        long endTime = System.currentTimeMillis();
        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes())
                .getRequest();
        String requestURI = request.getRequestURI();
        String remoteAddr = request.getRemoteAddr();
        String className = pjp.getSignature().getDeclaringTypeName();
        String method = pjp.getSignature().getName();
        logger.info(">>>>>>访问切面【VisitAspect】: [{}]时，来自ip为[{}]的客户端请求[{}]的接口[{}]",
                new Date(), remoteAddr, requestURI, method);
        logger.info(">>>>>>访问切面【VisitAspect】: 统计接口数据：当前线程:[{}],url地址:[{}],类名:[{}],接口名:[{}]," +
                "执行时间:[{}]毫秒", Thread.currentThread(), requestURI, className, method, (endTime - startTime));
        return retVal;
    }
}
